{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "47ae005b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[[ 0.1079, -0.4414, -0.5266],\n",
      "         [ 0.5029, -0.6185, -0.8355],\n",
      "         [-0.1999, -0.1668,  0.2397]],\n",
      "\n",
      "        [[ 0.3643, -0.1930, -0.5181],\n",
      "         [ 0.5197,  0.5771,  0.2790],\n",
      "         [ 0.2172,  0.4244,  0.5032]]], grad_fn=<TransposeBackward1>)\n",
      "tensor([[[-0.1999, -0.1668,  0.2397],\n",
      "         [ 0.2172,  0.4244,  0.5032]]], grad_fn=<StackBackward0>)\n"
     ]
    }
   ],
   "source": [
    "import torch.nn as nn\n",
    "import torch\n",
    "bs, T = 2, 3  # 批大小=2，序列长度=3\n",
    "input_size, hidden_size = 2, 3  # 输入特征维度=2，隐藏层维度=3\n",
    "input = torch.randn(bs, T, input_size)  # 随机初始化一个输入特征序列\n",
    "h_prev = torch.zeros(bs, hidden_size)  # 初始隐含状态\n",
    "\n",
    "# step1 调用PyTorch RNN API\n",
    "rnn = nn.RNN(input_size, hidden_size, batch_first=True)\n",
    "rnn_output, state_final = rnn(input, h_prev.unsqueeze(0))\n",
    "\n",
    "# print(rnn_output)\n",
    "# print(state_final)\n",
    "\n",
    "#step2 手写\n",
    "#"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e2478b26",
   "metadata": {
    "vscode": {
     "languageId": "latex"
    }
   },
   "source": [
    "1.  ​a​中文 NLP​​：\n",
    "    若使用 300 维词向量，则 input_size=300。\n",
    "    输入形状为 (batch_size, 句子最大长度, 300)。\n",
    "    ​b​时间序列预测​​：\n",
    "    若预测股价，输入是 [开盘价, 收盘价, 成交量]，则 input_size=3。\n",
    "\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "\n",
    "假设 batch_size=1, T=4（4个词）, input_size=3（词向量维度）\n",
    "input_sentence = torch.tensor([\n",
    "    [[0.1, 0.2, 0.3],  # \"这\"\n",
    "     [0.4, 0.5, 0.6],  # \"里\"\n",
    "     [0.7, 0.8, 0.9],  # \"有\"\n",
    "     [1.0, 1.1, 1.2]]  # \"人\"\n",
    "])  # 形状 (1, 4, 3)\n",
    "\n",
    " 定义RNN：input_size=词向量维度，hidden_size=5（自定义）\n",
    "rnn = nn.RNN(input_size=3, hidden_size=5, batch_first=True)\n",
    "\n",
    " 初始隐藏状态 (num_layers=1, batch_size=1, hidden_size=5)\n",
    "h0 = torch.zeros(1, 1, 5)\n",
    "\n",
    " 前向传播\n",
    "output, hn = rnn(input_sentence, h0)\n",
    "\n",
    "print(\"输出形状:\", output.shape)  # torch.Size([1, 4, 5])\n",
    "print(\"最终隐藏状态形状:\", hn.shape)  # torch.Size([1, 1, 5])\n",
    "2. \n",
    "在PyTorch的RNN中，rnn_output, state_final = rnn(input, h_prev.unsqueeze(0)) 的第二个返回值 state_final 是模型在所有时间步处理完输入序列后的 最终隐藏状态。以下是详细解释：\n",
    "\n",
    "state_final 的本质\n",
    "\n",
    "含义：  \n",
    "\n",
    "  state_final 是RNN处理完整个输入序列（所有时间步）后，最后一个时间步（t=T）的隐藏状态。  \n",
    "它包含了序列的全局时序信息，可以视为对输入序列的\"记忆总结\"。\n",
    "\n",
    "如果RNN有多个层，state_final 会包含每一层的最终隐藏状态。\n",
    "\n",
    "形状：  \n",
    "\n",
    "  (num_layers, batch_size, hidden_size)  \n",
    "num_layers：RNN的层数（默认1层）。\n",
    "\n",
    "batch_size：输入数据的样本数。\n",
    "\n",
    "hidden_size：隐藏状态的维度。\n",
    "\n",
    "代码示例说明\n",
    "\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "\n",
    "bs, T = 2, 3          # batch_size=2, 序列长度=3\n",
    "input_size = 2        # 输入特征维度\n",
    "hidden_size = 3       # 隐藏状态维度\n",
    "\n",
    "输入数据：(batch_size, seq_len, input_size)\n",
    "\n",
    "input = torch.randn(bs, T, input_size)  \n",
    "初始隐藏状态：(num_layers=1, batch_size, hidden_size)\n",
    "\n",
    "h_prev = torch.zeros(1, bs, hidden_size)  \n",
    "\n",
    "定义RNN\n",
    "\n",
    "rnn = nn.RNN(input_size, hidden_size, batch_first=True)\n",
    "\n",
    "前向传播\n",
    "\n",
    "rnn_output, state_final = rnn(input, h_prev)\n",
    "\n",
    "print(\"state_final形状:\", state_final.shape)  # torch.Size([1, 2, 3])\n",
    "print(\"state_final值:\\n\", state_final)\n",
    "\n",
    "输出解释：\n",
    "state_final 的形状是 [1, 2, 3]，表示：\n",
    "\n",
    "1层RNN，\n",
    "\n",
    "2个样本（bs=2），\n",
    "\n",
    "每个样本的最终隐藏状态是3维向量（hidden_size=3）。\n",
    "\n",
    "它的值类似于：\n",
    "\n",
    "  \n",
    "  tensor([[[ 0.1, -0.2,  0.3],  # 样本1的最终隐藏状态\n",
    "0.4,  0.0, -0.5]]]) # 样本2的最终隐藏状态\n",
    "\n",
    "  \n",
    "\n",
    "state_final 与 rnn_output 的关系\n",
    "\n",
    "返回值         含义 形状\n",
    "\n",
    "rnn_output 所有时间步的隐藏状态（序列输出） (batch_size, seq_len, hidden_size)\n",
    "state_final 最后一个时间步的隐藏状态 (num_layers, batch_size, hidden_size)\n",
    "\n",
    "关键区别：\n",
    "\n",
    "rnn_output[:, -1, :]（最后一个时间步的输出）理论上应等于 state_final[-1, :, :]（单层RNN时）。  \n",
    "\n",
    "但实际因实现细节（如梯度计算优化），两者可能有微小差异。\n",
    "\n",
    "多层RNN的情况\n",
    "\n",
    "如果RNN有多个层（num_layers > 1），state_final 会堆叠每一层的最终状态：\n",
    "rnn = nn.RNN(input_size, hidden_size, num_layers=2, batch_first=True)\n",
    "h0 = torch.zeros(2, bs, hidden_size)  # 初始状态：(2层, bs, hidden_size)\n",
    "output, state_final = rnn(input, h0)\n",
    "\n",
    "print(state_final.shape)  # torch.Size([2, 2, 3])\n",
    "\n",
    "此时 state_final 包含：\n",
    "\n",
    "state_final[0]：第一层的最终隐藏状态。\n",
    "\n",
    "state_final[1]：第二层的最终隐藏状态。\n",
    "\n",
    "实际应用场景\n",
    "\n",
    "序列到序列（Seq2Seq）任务：  \n",
    "\n",
    "  state_final 可作为编码器（Encoder）的上下文向量，传递给解码器（Decoder）。\n",
    "时间序列预测：  \n",
    "\n",
    "  用 state_final 初始化下一个序列的隐藏状态，保持时序连续性。\n",
    "句子分类：  \n",
    "\n",
    "  将 state_final 作为整个句子的表征，输入全连接层分类。\n",
    "\n",
    "总结\n",
    "state_final 是RNN处理完输入序列后的最终隐藏状态，形状为 (num_layers, batch_size, hidden_size)。\n",
    "\n",
    "它不同于 rnn_output（所有时间步的输出），而是序列的\"记忆总结\"。\n",
    "\n",
    "在多层RNN中，state_final 会包含每一层的最终状态。\n",
    "\n",
    "3.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0ddb1e4",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "cv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
